#include "ItemReference.h"
//#include "Defines.h"



#include <QCoreApplication>
#include <QTimer>
#include <QDebug>



namespace
{
QString REF_FIELD_NAME = "ref";

const char* TR_CONTEXT = "ItemReference";
const char* INVALID_REFERENCE_TEXT = QT_TRANSLATE_NOOP(TR_CONTEXT,"Invalid Reference");

int INTERNAL_VALUE_ROLE = Qt::UserRole+1;
}


ItemReference::ItemReference(AbstractItem* parent)
    : Item("Reference", parent)
{
    d = new Data();
}


ItemReference::~ItemReference()
{
}


bool ItemReference::isValid() const
{
    if (d->refItem.isNull()) return false;
    if (d->refName.isEmpty()) return false;
    if (d->refName != d->refItem->objectName()) return false;

    return true;
}


int ItemReference::fieldCount() const
{
    return (ItemReference::DataType_LAST - AbstractItem::DataType_FIRST + 1);
}


QString ItemReference::fieldName(const int &data_type) const
{
    switch (data_type)
    {
    case ReferenceData: return REF_FIELD_NAME;
    case Item::ValueData: return QString();
    default:            return Item::fieldName(data_type);
    }

    return QString::null;
}


int ItemReference::field(const QString &field_name) const
{
    if (field_name.toLower() == REF_FIELD_NAME.toLower())   return ReferenceData;

    return Item::field(field_name);
}


QString ItemReference::referencedName() const
{
    return data(ReferenceData).toString();
}


AbstractItem* ItemReference::referencedItem() const
{
    return d->refItem.data();
}


void ItemReference::onRefreshReferenceItem()
{
    if (!d->refItem.isNull())
    {
        disconnect(d->refItem.data(), SIGNAL(sigDirty()), this, SLOT(onReferenceItemDirty()));
    }


    AbstractItem* refItem = rootItem()->findChild<AbstractItem*>(d->refName);
    if (!refItem || IS_REFERENCE(refItem))
    {
        d->refName = QString::null;
        d->refItem = 0;
        setData(Item::ValueData, QVariant());
        emit sigDirty();
        return;
    }

    if (!parent() || refItem == parent()) return;

    foreach (QObject* obj, parent()->children())
    {
        ItemReference* otherRefItem = dynamic_cast<ItemReference*>(obj);
        if (!otherRefItem) continue;

        if (otherRefItem->referencedItem() == refItem) return;
    }

    d->refItem = refItem;
    d->refName = refItem->objectName();
    setData(Item::ValueData, d->refItem->data(Item::ValueData, Qt::EditRole));

    connect(d->refItem.data(), SIGNAL(sigDirty()), this, SLOT(onReferenceItemDirty()));
}



void ItemReference::onReferenceItemDirty()
{
    if (d->refItem.isNull()) return;

    d->refName = d->refItem->objectName();

    if (d->refItem->data(Item::ValueData, INTERNAL_VALUE_ROLE) == data(Item::ValueData, Qt::EditRole)) return;

    setData(Item::ValueData, d->refItem->data(Item::ValueData, Qt::EditRole));
}



QVariant ItemReference::customData(const int &data_type, int role) const
{
    switch (data_type)
    {
    case ReferenceData:
        {

            if (role == Qt::EditRole) return d->refName;

            if (role != Qt::DisplayRole)  return QVariant();

            if (!isValid()) return tr("Invalid Reference");

            return d->refItem->name();
        }
    case ValueData:
        {
            if (!isValid()) return QVariant();

            if (INTERNAL_VALUE_ROLE)
            {
                return Item::customData(data_type, Qt::EditRole);
            }

            if (Qt::DisplayRole)
            {
                return d->refItem->data(Item::ValueData, Qt::DisplayRole);
            }

            return QVariant();
        }
    }

    return QVariant();
}



void ItemReference::setCustomData(const int &data_type, const QVariant &value)
{
    switch (data_type)
    {
    case ReferenceData:
        if (value.toString() == INVALID_REFERENCE_TEXT) return;
        if (d->refName == value.toString()) return;

        d->refName = value.toString();
        QTimer::singleShot(0, this, SLOT(onRefreshReferenceItem()));
        return;

    case ValueData:
        Item::setCustomData(data_type, value);
        return;

    default:
        return;
    }


}



